using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using GameUtils;

namespace marbletrack
{
    public class ModelClass
    {
        private Model model_;

        public bool FlagTextured = false;

        //Flag to set which way around the triangles will be create by the physics engine
        public bool FlipNormalsFlag;

        //Vertex buffer variables
        private VertexPositionNormalTexture[][] meshVertexBuffers;
        public VertexPositionNormalTexture[][] MeshVertexBuffers
        {
            get { return meshVertexBuffers; }
        }

        //Index buffer variables
        private int[][] meshIndexBuffers;
        public int[][] MeshIndexBuffers
        {
            get { return meshIndexBuffers; }
        }

        VertexDeclaration vertexDeclaration;

        public ModelClass(string filename)
        {
            model_ = Game1.contentloader.Load<Model>(filename);

            //Sets the physics triangles to be created in reverse (Oposite order that XNA draws)
            FlipNormalsFlag = true;

            //Initialize each vertex and index buffer
            meshVertexBuffers = new VertexPositionNormalTexture[model_.Meshes.Count][];
            meshIndexBuffers = new int[model_.Meshes.Count][];

            //Get the vertex and index buffer for each mesh
            int i = 0;
            foreach (ModelMesh mesh in model_.Meshes)
            {
                meshVertexBuffers[i] = ((ModelVertexData)mesh.Tag).Vertices;
                meshIndexBuffers[i] = ((ModelVertexData)mesh.Tag).Indices;
                i++;
            }

            //Enable default lighting and set any other effects
            foreach (ModelMesh mesh in model_.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                }
            }

            //Vertex Declaration
            vertexDeclaration = new VertexDeclaration(Game1.Graphics.GraphicsDevice, VertexPositionNormalTexture.VertexElements);
        }

        //Load a custom texture
        public void LoadTexture(Texture2D texture)
        {
            foreach (ModelMesh mesh in model_.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.Texture = texture;
                    effect.TextureEnabled = FlagTextured;
                    effect.EnableDefaultLighting();
                    effect.LightingEnabled = true;

                    //effect.FogEnabled = true;
                    //effect.FogStart = 18000f;
                    //effect.FogEnd = 20000f;
                    //effect.FogColor = Color.White.ToVector3();
                }
            }
        }

        public void Draw(Matrix worldMatrix)
        {
            Game1.Graphics.GraphicsDevice.VertexDeclaration = vertexDeclaration;
            // Copy any parent transforms.
            Matrix[] transforms = new Matrix[model_.Bones.Count];
            model_.CopyAbsoluteBoneTransformsTo(transforms);

            // Check wheither cullmode need to be reversed (Note: XNA draws triangles in the oposite order to the physx engine)
            if (!FlipNormalsFlag)
                ReverseCullMode();
            
            // Draw the model. A model can have multiple meshes, so loop.
            foreach (ModelMesh mesh in model_.Meshes)
            {
                // This is where the mesh orientation is set, as well as our camera and projection.
                foreach (BasicEffect effect in mesh.Effects)
                {
                    //do not set the fog effects here it is slowing the game down
                    //effect.TextureEnabled = FlagTextured;
                    effect.World = worldMatrix;
                    effect.View = Game1.view;
                    effect.Projection = Game1.projectionMatrix;
                }
                // Draw the mesh, using the effects set above.
                mesh.Draw();
            }

            // Checks wheither cullmode needs to be switched back to default
            if (!FlipNormalsFlag)
                ReverseCullMode();
        }

        // Reverses Cull Mode
        private void ReverseCullMode()
        {
            if (Game1.Graphics.GraphicsDevice.RenderState.CullMode == CullMode.CullClockwiseFace)
                Game1.Graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
            else if (Game1.Graphics.GraphicsDevice.RenderState.CullMode == CullMode.CullCounterClockwiseFace)
                Game1.Graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace;
            else
                Game1.Graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
        }
    }
}
